package com.taokatao.cardmee.util;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Environment;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class DiskLruCacheUtils {

    private DiskLruCache mDiskLruCache;

    public static DiskLruCacheUtils open(Context context, String folderName) {
        try {
            DiskLruCacheUtils instance = new DiskLruCacheUtils();
            File cacheDir = instance.getDiskCacheDir(context, folderName);
            if (!cacheDir.exists()) cacheDir.mkdirs();

            instance.mDiskLruCache = DiskLruCache.open(cacheDir, getAppVersion(context), 1, 10 * 1024 * 1024);
            return instance;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    public synchronized boolean close() {
        try {
            mDiskLruCache.close();
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    public synchronized InputStream read(String key) {
        if (key != null) {
            try {
                DiskLruCache.Snapshot snapShot = mDiskLruCache.get(hashKeyForDisk(key));
                if (snapShot != null) {
                    return snapShot.getInputStream(0);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    public void write(final String key, final InputStream input) {
        try {
            DiskLruCache.Editor editor = mDiskLruCache.edit(hashKeyForDisk(key));
            if (editor != null) {
                OutputStream output = editor.newOutputStream(0);
                if (inputStreamToOutputStream(input, output)) {
                    editor.commit();
                } else {
                    editor.abort();
                }
            }
            mDiskLruCache.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public synchronized boolean remove(String key) {
        try {
            mDiskLruCache.remove(hashKeyForDisk(key));
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    public synchronized boolean clear() {
        try {
            mDiskLruCache.delete();
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    private String hashKeyForDisk(String key) {
        String cacheKey;
        try {
            final MessageDigest mDigest = MessageDigest.getInstance("MD5");
            mDigest.update(key.getBytes());
            cacheKey = bytesToHexString(mDigest.digest());
        } catch (NoSuchAlgorithmException e) {
            cacheKey = String.valueOf(key.hashCode());
        }
        return cacheKey;
    }

    private String bytesToHexString(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            String hex = Integer.toHexString(0xFF & bytes[i]);
            if (hex.length() == 1) {
                sb.append('0');
            }
            sb.append(hex);
        }
        return sb.toString();
    }

    File getDiskCacheDir(Context context, String uniqueName) {
        String cachePath;
        if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
            File file = context.getExternalCacheDir();
            if (file == null) {
                cachePath = context.getCacheDir().getPath();
            } else {
                cachePath = context.getExternalCacheDir().getPath();
            }
        } else {
            cachePath = context.getCacheDir().getPath();
        }
        return new File(cachePath + File.separator + uniqueName);
    }

    private static int getAppVersion(Context context) {
        try {
            PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
            return info.versionCode;
        } catch (NameNotFoundException e) {
            e.printStackTrace();
        }
        return 1;
    }

    static boolean inputStreamToOutputStream(InputStream input, OutputStream output) {
        BufferedInputStream in = new BufferedInputStream(input, 8 * 1024);
        BufferedOutputStream out = new BufferedOutputStream(output, 8 * 1024);
        try {
            int b;
            while ((b = in.read()) != -1) {
                out.write(b);
            }
            return true;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (out != null) out.close();
                if (in != null) in.close();
            } catch (final IOException e) {
                e.printStackTrace();
            }
        }
        return false;
    }
}
